package org.duiduo.common.tool.util;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream;
import org.apache.poi.util.IOUtils;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

/**
 * 压缩工具类
 *
 * @author liangze
 * @date 2025/8/6 10:40
 */
@Slf4j
public class PackUtil {

    /**
     * Gzip压缩
     *
     * @param outputFile 压缩文件
     * @param inputFiles 待压缩文件
     */
    public static void packTarGz(Path outputFile, Path... inputFiles) {
        try (OutputStream fOut = Files.newOutputStream(outputFile);
             BufferedOutputStream buffOut = new BufferedOutputStream(fOut);
             GzipCompressorOutputStream gzOut = new GzipCompressorOutputStream(buffOut);
             TarArchiveOutputStream tOut = new TarArchiveOutputStream(gzOut)) {

            for (Path inputFile : inputFiles) {
                // 跳过不存在的文件
                if (!Files.exists(inputFile)) {
                    continue;
                }
                TarArchiveEntry entry = new TarArchiveEntry(inputFile.toFile(), inputFile.getFileName().toString());
                tOut.putArchiveEntry(entry);
                // 如果是文件，写入内容
                if (Files.isRegularFile(inputFile)) {
                    try (InputStream input = Files.newInputStream(inputFile)) {
                        IOUtils.copy(input, tOut);
                    }
                }
                tOut.closeArchiveEntry();
            }
            tOut.finish();
        } catch (IOException e) {
            log.warn("Gzip压缩失败:", e);
            throw new RuntimeException("Gzip压缩失败");
        }
    }

    /**
     * Zip压缩
     *
     * @param outputFile 压缩文件
     * @param inputFiles 待压缩文件
     */
    public static void packZip(Path outputFile, Path... inputFiles) {
        try (OutputStream fOut = Files.newOutputStream(outputFile);
             ZipOutputStream zos = new ZipOutputStream(fOut)) {
            for (Path inputFile : inputFiles) {
                // 跳过不存在的文件
                if (!Files.exists(inputFile)) {
                    continue;
                }
                ZipEntry entry = new ZipEntry(inputFile.getFileName().toString());
                zos.putNextEntry(entry);
                // 如果是文件，写入内容
                if (Files.isRegularFile(inputFile)) {
                    try (InputStream input = Files.newInputStream(inputFile)) {
                        IOUtils.copy(input, zos);
                    }
                }
                zos.closeEntry();
            }
            zos.finish();
        } catch (IOException e) {
            log.warn("Zip压缩失败:", e);
            throw new RuntimeException("Zip压缩失败");
        }
    }

    /**
     * Gzip解压
     *
     * @param outputDir 解压目录
     * @param inputFile 压缩文件
     */
    public static void extractGzip(String outputDir, Path inputFile) {
        File outputDirFile = new File(outputDir);
        if (!outputDirFile.exists()) {
            outputDirFile.mkdirs();
        }

        try (InputStream is = Files.newInputStream(inputFile);
             BufferedInputStream bis = new BufferedInputStream(is);
             GzipCompressorInputStream gzis = new GzipCompressorInputStream(bis);
             TarArchiveInputStream tis = new TarArchiveInputStream(gzis)) {
            TarArchiveEntry entry;
            while ((entry = tis.getNextTarEntry()) != null) {
                if (entry.isDirectory()) {
                    continue;
                }
                File outputFile = new File(outputDir, entry.getName());
                File parent = outputFile.getParentFile();
                if (!parent.exists()) {
                    parent.mkdirs();
                }
                try (FileOutputStream fos = new FileOutputStream(outputFile)) {
                    IOUtils.copy(tis, fos);
                }
            }
        } catch (IOException e) {
            log.warn("Gzip解压失败:", e);
            throw new RuntimeException("Gzip解压失败");
        }
    }

    /**
     * Zip解压
     *
     * @param outputDir 解压目录
     * @param inputFile 压缩文件
     */
    public static void extractZip(String outputDir, Path inputFile) {
        File outputDirFile = new File(outputDir);
        if (!outputDirFile.exists()) {
            outputDirFile.mkdirs();
        }

        try (ZipInputStream zis = new ZipInputStream(Files.newInputStream(inputFile))) {
            ZipEntry entry;
            while ((entry = zis.getNextEntry()) != null) {
                if (entry.isDirectory()) {
                    continue;
                }
                File outputFile = new File(outputDir, entry.getName());
                File parent = outputFile.getParentFile();
                if (!parent.exists()) {
                    parent.mkdirs();
                }
                try (FileOutputStream fos = new FileOutputStream(outputFile)) {
                    IOUtils.copy(zis, fos);
                }
            }
            zis.closeEntry();
        } catch (IOException e) {
            log.warn("Zip解压失败:", e);
            throw new RuntimeException("Zip解压失败");
        }
    }

}
